const Koa = require('koa')
// 洋葱模型
const app = new Koa()
// 模板引擎 
const views = require('koa-views')
// 转换工具 
const json = require('koa-json')
// 错误处理插件
const onerror = require('koa-onerror')
// 中间件
const bodyparser = require('koa-bodyparser')
// 日志中间件
const logger = require('koa-logger')
// 引入路由文件
const index = require('./routes/index')
const users = require('./routes/users')
// 配置跨域
const cors = require("koa2-cors")
app.use(cors())//  ↓
// error handler 监听所有错误的
onerror(app)
//将 jwt挂载到全局 
const JWT = require("./utils/jwt")
app.context.jwt = JWT
// ctx.jwt.方法
//全局挂载 env配置
require("dotenv").config()
// Vue.prototype
app.context.env=process.env
// ctx.配置变量名
// 全局挂在 时间辅助类
let times = require("./utils/times")
app.context.time = times
// 挂载随机数  ctx.rand(6) => 6位验证码   
app.context.rand = (num=4)=>{
  let arr = []
  for(var i=0;i<num;i++){
    arr.push(Math.floor(Math.random()*10))
  }
  return arr.join('')
}

app.context.redis = require("zzmredis")

//接口限流  =》 计数器   密码桶=》通过脚本 每秒钟生成密码 
//定义一个计数器 用来记录每秒钟用户访问的次数
let userFindNum = 0
//定义上一秒用户访问的时间戳（秒） 
let lastFindTime = Math.floor(new Date().getTime()/1000)
app.use(async(ctx,next)=>{
  //定义当前用户访问的时间戳（秒）
  let nowFindTime = Math.floor(new Date().getTime()/1000)
  //如果上一次的访问时间 和 当前时间一致
  if(lastFindTime===nowFindTime){
    //判断访问次数 是否大于规定的次数 给前台一个500的报错
    if(userFindNum>process.env.FIND_NUM){
      ctx.status=500
      ctx.body={
        code:8000,
        codeInfo:"访问过于频繁，请稍后再试"
      }
      //如果 复合我们要求的访问次数内
    }else{
      //让计数器加加
      userFindNum++
      //再继续向下执行
      await next()// ↓
      
    }
    //如果两次访问时间不一致 说明用户允许访问
  }else{
    //将上一次的访问时间 定为当前时间
    lastFindTime =nowFindTime
    //初始次数为1
    userFindNum=1
    //继续向下执行
    await next()// ↓
  }
})
// middlewares ↓
app.use(bodyparser({
  enableTypes:['json', 'form', 'text']
}))
app.use(json())//↓
app.use(logger())//↓
app.use(require('koa-static')(__dirname + '/public'))//↓
//↓
app.use(views(__dirname + '/views', {
  extension: 'ejs'
}))

// logger ↓
app.use(async (ctx, next) => {
  const start = new Date()
  await next()//↓
  const ms = new Date() - start
  console.log(`请求方式：${ctx.method}请求地址： ${ctx.url} - 响应时间： ${ms}ms`)
})
//↓ 对常见状态码 进行错误处理 
app.use(async (ctx,next)=>{
  await next()//↓
  if(ctx.status==404){
    ctx.body={
      code:404,
      codeInfo:"您访问的资源不存在！"
    }
  }else if(ctx.status==500){
     ctx.body={
      code:500,
      codeInfo:"服务端程序报错！"
    }
  }
})

// routes ↓
app.use(index.routes(), index.allowedMethods())
app.use(users.routes(), users.allowedMethods())

// error-handling
app.on('error', (err, ctx) => {
  console.error('server error', err, ctx)
});

module.exports = app
//koa2 =>中间件  最大特点就是洋葱模型 =》 应用中间键  第三方中间件  路由中间件  错误中间件

